package com.tyros.resource.storage;

import com.aliyun.oss.OSS;
import com.aliyun.oss.OSSClientBuilder;
import com.aliyun.oss.model.GetObjectRequest;
import com.aliyun.oss.model.OSSObject;
import com.baomidou.mybatisplus.core.toolkit.StringPool;
import com.tyros.common.exception.BaseException;
import com.tyros.common.utils.LogUtils;
import com.tyros.resource.config.property.StorageProperties;
import com.tyros.resource.constant.ResourceMessage;
import com.tyros.resource.modules.file.dto.FileDTO;
import com.tyros.resource.strategy.AbstractFileStrategy;
import com.tyros.resource.tool.RangeParser;
import lombok.extern.slf4j.Slf4j;
import org.springframework.web.multipart.MultipartFile;

import javax.annotation.PostConstruct;
import javax.annotation.Resource;
import java.io.InputStream;
import java.util.Objects;

/**
 * @author zhangshuaiyin
 * @date 2022/2/20 12:32
 */
@Slf4j
public class AliOssStorageService extends AbstractFileStrategy {

    @Resource
    private StorageProperties storageProperties;

    private static String endpoint;
    private static String bucketName;
    private static OSS ossClient;

    @PostConstruct
    public void init() {
        endpoint = storageProperties.getAli().getEndpoint();
        String accessKeyId = storageProperties.getAli().getAccessKeyId();
        String accessKeySecret = storageProperties.getAli().getAccessKeySecret();
        bucketName = storageProperties.getAli().getBucketName();
        try {
            ossClient = new OSSClientBuilder().build(endpoint, accessKeyId, accessKeySecret);
        } catch (Exception e) {
            log.error("连接阿里云异常: ", e);
            BaseException.throwExp(ResourceMessage.OSS_CLIENT_INIT_ERROR);
        }
    }

    @Override
    protected void upload(MultipartFile file, FileDTO fileDTO) {
        this.transferObjectKey(fileDTO);
        try {
            ossClient.putObject(bucketName, fileDTO.getObjectKey(), file.getInputStream());
        } catch (Exception e) {
            log.error("上传文件失败: ", e);
            BaseException.throwExp(ResourceMessage.UPLOAD_FILE_ERROR);
        }
        fileDTO.setPath(this.getPath(fileDTO.getObjectKey()));
    }

    @Override
    protected void delete(FileDTO file) {
        if (ossClient.doesObjectExist(bucketName, file.getObjectKey())) {
            ossClient.deleteObject(bucketName, file.getObjectKey());
        }
    }

    @Override
    protected InputStream download(FileDTO fileDTO, RangeParser.Range range) {
        OSSObject object;

        if (Objects.nonNull(range)) {
            GetObjectRequest getObjectRequest = new GetObjectRequest(bucketName, fileDTO.getObjectKey());
            // 对于大小为1000 Bytes的文件，正常的字节范围为0~999。
            // 获取0~999字节范围内的数据，包括0和999，共1000个字节的数据。如果指定的范围无效（比如开始或结束位置的指定值为负数，或指定值大于文件大小），则下载整个文件。
            getObjectRequest.setRange(range.getStart(), range.getEnd());

            // 范围下载。
            object = ossClient.getObject(getObjectRequest);
            LogUtils.info(log, "范围下载数据, start: {}, end: {}", range.getStart(), range.getEnd());
        } else {
            object = ossClient.getObject(bucketName, fileDTO.getObjectKey());
        }
        return object.getObjectContent();
    }

    @Override
    public String getPath(String objectKey) {
        // https://bucketexample.oss-cn-hangzhou.aliyuncs.com/example/example.jpg
        return "https://" + bucketName + StringPool.DOT + endpoint + StringPool.SLASH + objectKey;
    }

    private void transferObjectKey(FileDTO fileDTO) {
        fileDTO.setObjectKey(fileDTO.getObjectKey().replaceAll("\\\\", StringPool.SLASH));
    }

    public static void main(String[] args) {
        String objectKey = "2020/02/26/file.txt";
        System.out.println(objectKey.replaceAll("\\\\", StringPool.SLASH));
    }
}
